package com.yonyou.pmclouds.workflow.service;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.workflow.entity.ProcessDataSynResultVO;
import com.yonyou.pmclouds.workflow.entity.ProcessDataSynVO;
import com.yonyou.pmclouds.workflow.entity.UserAndUserGroupVO;
import com.yonyou.pmclouds.workflow.util.ProcessServiceConst;
import com.yonyou.pmclouds.workflow.util.WorkFlowConst;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import yonyou.bpm.rest.IdentityService;
import yonyou.bpm.rest.exception.RestException;
import yonyou.bpm.rest.request.identity.*;

import java.util.*;

/**
 * 云审批基础数据同步：租户信息、回调函数
 *
 * @author zhangzhonghao
 */

@Slf4j
@Service
public class BaseDataSynService {

    @Value("${bpmrest.tenant}")
    private String tenant;

    @Value("${bpmrest.callbackurl}")
    private String callbackurl;

    /**
     * 租户同步到云审批
     *
     * @return 同步结果
     */
    public ProcessDataSynResultVO tenantDataSyn(String tenantInfo, String userId, String tenantId, String sysId)
            throws RestException, BusinessException {
        IdentityService identityService = getDefaultIdentityService(userId, tenantId);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("同步租户：");

        // 删除租户信息
//        this.deleteTenantInfo(userId, tenantId);

        // 从租户中心获取当前租户信息
        JSONObject jsonObject = JSONObject.parseObject(tenantInfo);
        JSONObject tenantJsonObject = (JSONObject) jsonObject.get("tenant");
        // 将同步结果记录到日志表
        ProcessDataSynVO synVO = this.getDataSynVO(userId, tenantId);
        synVO.setDataType(ProcessServiceConst.DATA_TYPE_TENANT);
        if (tenantJsonObject != null) {
            TenantResourceParam resourceParam = new TenantResourceParam();
            String tenantName = tenantJsonObject.getString("tenantName");
            resourceParam.setId(tenantId);
            resourceParam.setName(tenantName);
            resourceParam.setTenantContent(getTenantContent(sysId));
            // 不传parent时，默认会存为当前租户ID，会导致无法删除
            resourceParam.setParentCode(tenant);
            resourceParam.setCode(tenantJsonObject.getString("tenantCode"));
            // 同步之前先判断租户是否存在，如果存在则更新用户信息，0为新增
            if (tenantIsExist(userId, tenantId)) {
                resourceParam.setRevision(1);
            }
            // 保存租户信息到云审批
            JsonNode retNode = (JsonNode) identityService.saveTenant(resourceParam);
            if (retNode == null) {
                throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);
            }
            synVO.setSynResult(String.valueOf(retNode.get(ProcessServiceConst.FIELD_ERROR_CODE).intValue()));
            synVO.setSynMessage(retNode.get(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue());
            synVO.setSynObject("tenantId:" + tenantId + "_tenantName:" + tenantName + "_systemCode:" + sysId);
            if (ProcessServiceConst.SUCCESS_UPDATE.equalsIgnoreCase(synVO.getSynResult()) ||
                    ProcessServiceConst.SUCCESS.equalsIgnoreCase(synVO.getSynMessage()) ||
                    ProcessServiceConst.ERROR_CODE_TENANT_ID_EXISTS.equals(synVO.getSynResult())) {
                stringBuilder.append("成功");
            } else {
                stringBuilder.append("失败，失败原因：").append(synVO.getSynMessage());
            }
        } else {
            synVO.setSynResult("error");
            synVO.setSynMessage("租户[" + tenantId + "]从租户中心获取信息为空");
            stringBuilder.append("失败，失败原因：").append(synVO.getSynMessage());
        }

        ProcessDataSynResultVO resultVO = new ProcessDataSynResultVO();
        resultVO.setSynResult(stringBuilder.toString());
        List<ProcessDataSynVO> dataSynVOList = new ArrayList<>();
        dataSynVOList.add(synVO);
        resultVO.setDataSynVOList(dataSynVOList);

        return resultVO;
    }

    /**
     * 将角色转为用户组同步到云审批
     *
     * @return 同步结果
     */
    public ProcessDataSynResultVO roleDataSyn(List<UserAndUserGroupVO> userGroupVOList,
                                              String userId, String tenantId) throws RestException, BusinessException {
        StringBuilder stringBuilder = new StringBuilder("，同步用户组：成功");
        StringBuilder errorBuilder = new StringBuilder("，失败原因：");
        int successRoleCount = 0;
        int failRoleCount = 0;
        List<ProcessDataSynVO> dataSynVOList = new ArrayList<>();

        if (userGroupVOList != null && userGroupVOList.size() > 0) {
            IdentityService identityService = getDefaultIdentityService(userId, tenantId);

            // 删除该租户下的用户组和关联关系
            this.deleteUserInfo(userId, tenantId);

            for (UserAndUserGroupVO groupVO : userGroupVOList) {
                UserGroupResourceParam groupResourceParam = new UserGroupResourceParam();
                groupResourceParam.setCode(groupVO.getUserGroupCode());
                groupResourceParam.setName(groupVO.getUserGroupName());
                groupResourceParam.setTenantId(tenantId);
                // 同步信息至云审批
                JsonNode userGroupNode = (JsonNode) identityService.saveUserGroup(groupResourceParam);
                if (userGroupNode == null) {
                    throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);
                }
                ProcessDataSynVO synVO = this.getDataSynVO(userId, tenantId);
                synVO.setSynObject("roleCode:" + groupResourceParam.getCode() + "_roleName:" + groupResourceParam.getName());
                synVO.setSynResult(String.valueOf(userGroupNode.get(ProcessServiceConst.FIELD_ERROR_CODE).intValue()));
                synVO.setSynMessage(userGroupNode.get(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue());
                synVO.setDataType(ProcessServiceConst.DATA_TYPE_USER_GROUPS);

                if (ProcessServiceConst.SUCCESS.equalsIgnoreCase(userGroupNode.get(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue()) ||
                        ProcessServiceConst.ERROR_CODE_ROLE_CODE_EXISTS.equals(synVO.getSynResult())) {
                    successRoleCount++;
                    String userGroupId = userGroupNode.get(ProcessServiceConst.FIELD_ID).textValue();
                    if (StringUtils.isEmpty(userGroupId)) {
                        // 根据角色ID获取下面所有用户
                        this.userLinkSyn(userGroupId, userId, tenantId, groupVO.getUserIdList(), dataSynVOList);
                    }
                } else {
                    failRoleCount++;
                    errorBuilder.append(synVO.getSynMessage()).append(",");
                }

                dataSynVOList.add(synVO);

            }
            stringBuilder.append(successRoleCount).append("条").append("，失败").append(failRoleCount).append("条");
            if (failRoleCount > 0) {
                stringBuilder.append(errorBuilder);
            }
        } else {
            stringBuilder.append(successRoleCount).append("条").append("，失败").append(failRoleCount).append("条");
        }

        ProcessDataSynResultVO resultVO = new ProcessDataSynResultVO();
        resultVO.setSynResult(stringBuilder.toString());
        resultVO.setDataSynVOList(dataSynVOList);
        return resultVO;
    }

    /**
     * 用户组和用户关联关系同步
     */
    private void userLinkSyn(String userGroupId, String operatorId, String tenantId, List<String> userIdList,
                             List<ProcessDataSynVO> dataSynVOList) throws RestException, BusinessException {
        IdentityService identityService = getDefaultIdentityService(operatorId, tenantId);
        if (userIdList != null && userIdList.size() > 0) {
            for (String userId : userIdList) {
                UserLinkResourceParam linkResourceParam = new UserLinkResourceParam();
                linkResourceParam.setUserId(userId);
                linkResourceParam.setTenantId(tenantId);
                linkResourceParam.setTargetId(userGroupId);
                linkResourceParam.setType(ProcessServiceConst.USER_LINK_TYPE);
                // 保存关联关系至云审批
                JsonNode userLinkNode = (JsonNode) identityService.saveUserLink(linkResourceParam);
                if (userLinkNode == null) {
                    throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);
                }
                ProcessDataSynVO synVO = this.getDataSynVO(userId, tenantId);
                synVO.setDataType(ProcessServiceConst.DATA_TYPE_USER_LINKS);
                synVO.setSynMessage(userLinkNode.get(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue());
                synVO.setSynResult(String.valueOf(userLinkNode.get(ProcessServiceConst.FIELD_ERROR_CODE).intValue()));
                synVO.setSynObject("userId:" + userId + "_userGroupId:" + userGroupId);
                // 将同步信息插入日志表
                dataSynVOList.add(synVO);
            }
        }

    }

    /**
     * 同步前先删除该租户下的基础数据，因为从角色中心获取的没有修改时间，无法做增量，并且已删除的角色获取不到，
     * 为保持信息同步，先删除再重新插入
     *
     * @throws RestException 异常
     */
    private void deleteUserInfo(String userId, String tenantId) throws RestException, BusinessException {
        IdentityService identityService = getDefaultIdentityService(userId, tenantId);
        // 删除该租户下所有关联关系
        UserLinkQueryParam linkQueryParam = new UserLinkQueryParam();
        linkQueryParam.setTenantId(tenantId);
        JsonNode linkNodes = (JsonNode) identityService.queryUserLinks(linkQueryParam);
        for (JsonNode linkNode : linkNodes.get(ProcessServiceConst.FIELD_DATA)) {
            String linkId = linkNode.get(ProcessServiceConst.FIELD_ID).textValue();
            identityService.deleteUserLink(linkId);
        }
        // 删除该租户下面的所有用户组
        UserGroupQueryParam queryParam = new UserGroupQueryParam();
        queryParam.setTenantId(tenantId);
        JsonNode userGroupRetNode = (JsonNode) identityService.queryUserGroups(queryParam);
        for (JsonNode userGroupNode : userGroupRetNode.get(ProcessServiceConst.FIELD_DATA)) {
            String userGroupId = userGroupNode.get(ProcessServiceConst.FIELD_ID).textValue();
            identityService.deleteUserGroup(userGroupId);
        }
    }

    /**
     * 删除租户信息和租户关联关系
     */
    private void deleteTenantInfo(String userId, String tenantId) throws RestException, BusinessException {
        IdentityService identityService = getDefaultIdentityService(userId, tenantId);
        JsonNode tenantNode = (JsonNode) identityService.getTenant(tenantId);
        if (tenantNode == null) {
            throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);
        }
        if (tenantNode.findValue(ProcessServiceConst.FIELD_ERROR_CODE).intValue() == ProcessServiceConst.ERROR_CODE_TENANT_NO_FIND
                && tenantNode.findValue(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue().contains("Can not find data with id")) {
            return;
        }

        TenantLinkQueryParam queryParam = new TenantLinkQueryParam();
        queryParam.setTenantId(tenantId);
        JsonNode tenantLinkNode = (JsonNode) identityService.queryTenantLinks(queryParam);
        if (tenantLinkNode == null) {
            throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);
        }
        ArrayNode arrayNode = (ArrayNode) tenantLinkNode.findValue(ProcessServiceConst.FIELD_DATA);
        if (arrayNode != null && arrayNode.size() > 0) {
            for (JsonNode linkNode : arrayNode) {
                identityService.deleteTenantLink(linkNode.findValue(ProcessServiceConst.FIELD_ID).textValue());
            }
        }

        identityService.deleteTenant(tenantId);

    }

    /**
     * 注册云审回调监听
     *
     * @return 注册结果
     */
    public ProcessDataSynResultVO registerCallBackListener(String userId, String tenantId) throws BusinessException {
        IdentityService identityService = getDefaultIdentityService(userId, tenantId);

        JsonNode jsonNode = this.queryListenerByCode(tenantId, identityService);

        BasicDataResourceParam param = new BasicDataResourceParam();
        param.setCode(WorkFlowConst.CALLBACK_LISTENER_CODE + "_" + tenantId);
        param.setName(WorkFlowConst.CALLBACK_LISTENER_NAME);
        param.setType(WorkFlowConst.CALLBACK_LISTENER_TYPE);
        //暂时写死
        param.setToken("uuu");
        param.setUrl(callbackurl);
        param.setTenantId(tenantId);
        param.setSource(ApplicationConsts.APPLICATION_ID);

        ProcessDataSynResultVO resultVO = new ProcessDataSynResultVO();
        List<ProcessDataSynVO> dataSynVOList = new ArrayList<>();
        resultVO.setDataSynVOList(dataSynVOList);

        if (jsonNode != null && jsonNode.size() > 0) {
            for (JsonNode node : jsonNode) {
                if (node.get("id") == null || StringUtils.isEmpty(node.get("id").textValue()))
                    continue;
                String id = node.get("id").textValue();
                String source = node.get("source").textValue();
                param.setId(id);
                param.setSource(source);
                insertOrUpdateListener(userId, tenantId, param, identityService, resultVO);
            }
        } else {
            insertOrUpdateListener(userId, tenantId, param, identityService, resultVO);
        }

        return resultVO;

    }

    private void insertOrUpdateListener(String userId, String tenantId, BasicDataResourceParam param,
                                                          IdentityService identityService, ProcessDataSynResultVO resultVO) throws BusinessException {
        StringBuilder stringBuilder = new StringBuilder("，注册回调接口：");
        try {
            Object result = identityService.insertBasicData(param);
            if (result == null)
                throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);

            JsonNode insertResult = (JsonNode) result;

            // 将注册结果记录到日志表
            ProcessDataSynVO synVO = this.getDataSynVO(userId, tenantId);
            synVO.setDataType(ProcessServiceConst.DATA_TYPE_CALLBACK);
            synVO.setSynObject(callbackurl);
            synVO.setSynResult(String.valueOf(insertResult.findValue(ProcessServiceConst.FIELD_ERROR_CODE).intValue()));
            synVO.setSynMessage(insertResult.findValue(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue());
            if (ProcessServiceConst.SUCCESS.equalsIgnoreCase(synVO.getSynMessage())) {
                stringBuilder.append("成功");
            } else {
                stringBuilder.append("失败，失败原因为：").append(synVO.getSynMessage());
            }

            resultVO.setSynResult(stringBuilder.toString());
            resultVO.getDataSynVOList().add(synVO);

        } catch (RestException e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 新增回调监听前，先删除原有监听
     * 异常先抛到上一层，统一记录处理
     */
    private void removeExistListener(String userId, String tenantId) throws BusinessException {
        IdentityService identityService = getDefaultIdentityService(userId, tenantId);

        JsonNode jsonNode = this.queryListenerByCode(tenantId, identityService);

        for (JsonNode node : jsonNode) {

            if (node.get("code") == null || StringUtils.isEmpty(node.get("code").textValue()))
                continue;

            String code = node.get("code").textValue();
            try {
                // 该接口存在问题，如果code不唯一，无法删除成功
                Object deleteResult = identityService.deleteBasicData(code, tenantId);
            } catch (RestException e) {
                log.error(e.getMessage(), e);
                throw new BusinessException(e);
            }

        }

    }

    private JsonNode queryListenerByCode(String tenantId, IdentityService identityService) throws BusinessException {
        BasicdataQueryParam param = new BasicdataQueryParam();
        param.setType(WorkFlowConst.CALLBACK_LISTENER_TYPE);
        // param.setSource(ApplicationConsts.APPLICATION_ID);
        param.setCode(WorkFlowConst.CALLBACK_LISTENER_CODE + "_" + tenantId);
        param.setTenantId(tenantId);

        Object queryResult;
        try {
            queryResult = identityService.queryBasicdatas(param);
        } catch (RestException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e);
        }

        if (queryResult == null)
            throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);

        return ((JsonNode) queryResult).get("data");
    }

    private String getTenantContent(String sysId) {
        Map<String, String> map = new HashMap<>();
        map.put("systemCode", sysId);
        return JSONObject.toJSONString(map);
    }

    private boolean tenantIsExist(String userId, String tenantId) throws RestException, BusinessException {
        IdentityService identityService = getDefaultIdentityService(userId, tenantId);
        JsonNode tenantNode = (JsonNode) identityService.getTenant(tenantId);
        if (tenantNode == null) {
            throw new BusinessException(WorkFlowConst.YS_NULL_RESP_MSG);
        }
        return "ok".equalsIgnoreCase(tenantNode.findValue(ProcessServiceConst.FIELD_ERROR_MESSAGE).textValue()) &&
                tenantNode.findValue(ProcessServiceConst.FIELD_ERROR_CODE).intValue() == 0;
    }

    /**
     * 给VO赋默认值
     *
     * @return 信息同步日志VO
     */
    private ProcessDataSynVO getDataSynVO(String userId, String tenantId) {
        Date currentDate = Calendar.getInstance().getTime();
        ProcessDataSynVO synVO = new ProcessDataSynVO();
        synVO.setPkTenant(tenantId);
        synVO.setCreationtime(currentDate);
        synVO.setModifytime(currentDate);
        synVO.setCreator(userId);
        synVO.setModifier(userId);
        synVO.setLastSynDate(currentDate);
        return synVO;
    }

    private IdentityService getDefaultIdentityService(String userId, String tenantId) throws BusinessException {
        return (IdentityService) ProcessServiceFactory
                .getProcessService(ProcessServiceFactory.IDENTITY_SERVICE, userId, tenantId);
    }
}
